#include "CProcessCycle.h"
#include "CLogger.h"
#include "CProcessAttribute.h"
#include "CConfigParser.h"
#include "CLogicSocket.h"
#include <signal.h>
#include <stdio.h>
#include <errno.h>
#include <stdlib.h>

char CProcessCycle::m_szMasterProcessName[] = "master process";

void CProcessCycle::startWorkerProcess(int nProcessNum)
{
	for (size_t i = 0; i < nProcessNum; i++)
	{
		spawnProcess(i, "worker process");
	}
}

int CProcessCycle::spawnProcess(int iNum, const char* pProcName)
{
	pid_t pid = fork();
	switch (pid)
	{
	case -1:
		CLogger::logErrorCore(LOG_ALERT, errno, "spawnProcess() fork()产生子进程num = %d, procname = \"%s\"失败！", iNum, pProcName);
		return -1;
	case 0:	//子进程分支
		CProcessAttribute::m_siParentPid = CProcessAttribute::m_siPid;
		CProcessAttribute::m_siPid = getpid();
		workerProcessCycle(iNum, pProcName);
		break;
	default:
		break;
	}
	return 0;
}

void CProcessCycle::workerProcessCycle(int nNum, const char* pProcName)
{
	//设置进程的类型，是worker进程
	CProcessAttribute::m_snProcessType = PROCESS_WORKER;
	//子进程初始化
	workerProcessInit(nNum);
	CProcessAttribute::setProcTitle(pProcName);
	CLogger::logErrorCore(LOG_NOTICE, 0, "%s %P [worker进程]启动并开始运行......！", pProcName, CProcessAttribute::m_siPid);

	for (; ;)
	{
		//处理网络和定时器事件
		g_clLogicSocket.epollProcessEvents(-1);
		g_clLogicSocket.printStatisticsInfo();
	}

	g_clThreadPool.stopAll(); //停止线程池
	g_clLogicSocket.shutdown(); //关闭socket
}

// 子进程初始化工作
void CProcessCycle::workerProcessInit(int nNum)
{
	sigset_t set;	//信号集
	sigemptyset(&set);	//清空信号集
	if (sigprocmask(SIG_SETMASK, &set, NULL) == -1)	//原来是屏蔽那10个信号[防止fork()期间收到信号导致混乱]，现在不再屏蔽任何信号[接收任何信号]
	{
		CLogger::logErrorCore(LOG_ALERT, errno, "workerProcessInit()中sigprocmask()失败！");
	}

	// 线程池代码
	CConfigParser* pConfig = CConfigParser::getInstance();
	int nTmpThreadNum = pConfig->getIntDefault("ProcMsgRecvWorkThreadCount", 5);	//处理接收到的消息的线程池中线程数量
	if (g_clThreadPool.create(nTmpThreadNum) == false)
	{
		//内存没有释放，简单粗暴退出
		exit(-2);
	}
	sleep(1);

	if (g_clLogicSocket.initInChild() == false)	//初始化子进程需要具备的一些多线程能力相关的信息
	{
		//内存没有释放，简单粗暴退出
		exit(-2);
	}

	//初始化epoll相关内容，同时往监听socket上增加监听事件，从而让监听端口履行其职责
	g_clLogicSocket.epollInit();
}

void CProcessCycle::masterProcessCycle()
{
	sigset_t set;	//信号集
	sigemptyset(&set);	//清空信号集

	//下列这些信号在执行本函数期间不希望收到（保护不希望由信号中断的代码临界区）
	//建议fork()子进程时学习这种写法，防止信号的干扰
	sigaddset(&set, SIGCHLD);	//子进程状态改变
	sigaddset(&set, SIGALRM);	//定时器超时
	sigaddset(&set, SIGIO);		//异步I/O
	sigaddset(&set, SIGINT);	//终端中断符
	sigaddset(&set, SIGHUP);	//连接断开
	sigaddset(&set, SIGUSR1);	//用户定义信号
	sigaddset(&set, SIGUSR2);	//用户定义信号
	sigaddset(&set, SIGWINCH);	//终端窗口大小改变
	sigaddset(&set, SIGTERM);	//终止
	sigaddset(&set, SIGQUIT);	//终端退出符

	// 设置此时无法接受的信号，阻塞期间，你发过来的上述信号，多个会被合并为一个，暂存着，等放开信号屏蔽后才能收到这些信号
	if (sigprocmask(SIG_BLOCK, &set, NULL) == -1)
	{
		CLogger::logErrorCore(LOG_ALERT, errno, "masterProcessCycle()中sigprocmask()失败！");
	}

	// 设置主进程标题
	size_t size;
	int i;
	size = sizeof(m_szMasterProcessName);
	size += CProcessAttribute::m_snArgvNeedMem;
	if (size < 1000)
	{
		char szTitle[1000] = { 0 };
		strcpy(szTitle, (const char*)m_szMasterProcessName);
		strcat(szTitle, " ");
		for (size_t i = 0; i < CProcessAttribute::m_snOSArgc; i++)
		{
			strcat(szTitle, CProcessAttribute::m_slpOSArgv[i]);
		}
		CProcessAttribute::setProcTitle(szTitle);
		CLogger::logErrorCore(LOG_NOTICE, 0, "%s %P [master进程]启动并开始运行......!", szTitle, CProcessAttribute::m_siPid);
	}

	//从配置文件中读取要创建的worker进程数量
	CConfigParser* pConfig = CConfigParser::getInstance();
    int nWorkerProcess = pConfig->getIntDefault("WorkerProcesses", 1);	//从配置文件中得到要创建的worker进程数量

    if(nWorkerProcess > 0) {
        startWorkerProcess(nWorkerProcess);	//这里创建worker子进程

        //创建子进程后，父进程的流程会回到这里，子进程不会到这一步
        sigemptyset(&set);
        for (; ;)
        {
            //sigsuspend是一个原子操作，包含4个步骤
            //1.根据给定的参数设置新的mask，并阻塞当前进程[set是个空集，不阻塞任何信号，也就是说可以收到任何信号]
            //2.一旦收到信号，就恢复原先的信号屏蔽字[我们原先调用sigprocmask()的mask在上边设置的阻塞多达10个信号，从而保证我们下边的执行流程不会再被其他信号截断]
            //3.调用该信号对于的信号处理函数
            //4.信号处理函数返回后，sigsuspend返回，使程序继续走下去
            sigsuspend(&set);	//阻塞在这里，等待一个信号，此时进程是挂起的，不占用CPU时间，只有收到信号才会被唤醒（返回）
            //master进程完全靠信号驱动干活
        }
    } else {
        workerProcessInit(0);
        for (; ;)
        {
            //处理网络和定时器事件
            g_clLogicSocket.epollProcessEvents(-1);
            g_clLogicSocket.printStatisticsInfo();
        }

        g_clThreadPool.stopAll(); //停止线程池
        g_clLogicSocket.shutdown(); //关闭socket
    }
}
